package com.zfy.tingshu.search.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.BeanCopier;
import cn.hutool.extra.pinyin.PinyinUtil;
import cn.hutool.json.JSONObject;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.aggregations.Aggregate;
import co.elastic.clients.elasticsearch._types.aggregations.TermsAggregation;
import co.elastic.clients.elasticsearch._types.query_dsl.BoolQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.NestedQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.TermsQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.TermsQueryField;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.CompletionSuggest;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.core.search.HitsMetadata;
import co.elastic.clients.elasticsearch.core.search.Suggestion;
import com.alibaba.fastjson.JSON;
import com.zfy.tingshu.album.client.AlbumInfoFeignClient;
import com.zfy.tingshu.album.client.CategoryFeignClient;
import com.zfy.tingshu.album.client.impl.CategoryDegradeFeignClient;
import com.zfy.tingshu.common.constant.RedisConstant;
import com.zfy.tingshu.common.execption.GuiguException;
import com.zfy.tingshu.common.result.Result;
import com.zfy.tingshu.common.util.PinYinUtils;
import com.zfy.tingshu.model.album.*;
import com.zfy.tingshu.model.search.AlbumInfoIndex;
import com.zfy.tingshu.model.search.AttributeValueIndex;
import com.zfy.tingshu.model.search.SuggestIndex;
import com.zfy.tingshu.query.search.AlbumIndexQuery;
import com.zfy.tingshu.search.config.ThreadPoolExecutorConfig;
import com.zfy.tingshu.search.repository.AlbumIndexRepository;
import com.zfy.tingshu.search.repository.SuggestIndexRepository;
import com.zfy.tingshu.search.service.SearchService;
import com.zfy.tingshu.user.client.UserInfoFeignClient;
import com.zfy.tingshu.vo.album.AlbumAttributeValueVo;
import com.zfy.tingshu.vo.album.AlbumInfoVo;
import com.zfy.tingshu.vo.album.AlbumStatVo;
import com.zfy.tingshu.vo.search.AlbumInfoIndexVo;
import com.zfy.tingshu.vo.search.AlbumSearchResponseVo;
import com.zfy.tingshu.vo.user.UserInfoVo;
import io.swagger.v3.oas.annotations.Operation;

import jakarta.json.JsonObject;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.data.elasticsearch.core.suggest.Completion;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.function.Function;
import java.util.stream.Collectors;

import cn.hutool.core.bean.copier.CopyOptions;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;


@Slf4j
@Service
@SuppressWarnings({"all"})
public class SearchServiceImpl implements SearchService {

    @Autowired
    private AlbumInfoFeignClient albumInfoFeignClient;

    @Autowired
    private UserInfoFeignClient userInfoFeignClient;

    @Autowired
    private CategoryFeignClient categoryFeignClient;

    @Autowired
    private ThreadPoolExecutorConfig threadPoolExecutorConfig;
    @Autowired
    private AlbumIndexRepository albumIndexRepository;
    @Autowired
    private ElasticsearchClient elasticsearchClient;
    @Autowired
    private SuggestIndexRepository suggestIndexRepository;
    @Qualifier("redisTemplate")
    @Autowired
    private RedisTemplate redisTemplate;
    @Value("${ranking.dimension.array}")
    private String rankingDimensionArray;

    @Autowired
    private RedissonClient redissonClient;


    @Override
//    @Async//异步方法
    public void upperAlbum(Long albumId) {
        //需要使用AlbumInfoIndex
        AlbumInfoIndex albumInfoIndex = new AlbumInfoIndex();

        //查询专辑
        CompletableFuture<AlbumInfo> albumInfoCompletableFuture = CompletableFuture.supplyAsync(() -> {
            //赋值:album_info: 表数据
            Result<AlbumInfo> albumInfo = albumInfoFeignClient.getAlbumInfo(albumId);
            Assert.notNull(albumInfo, "查询专辑信息失败");
            //获取到专辑对象
            AlbumInfo data = albumInfo.getData();
            Assert.notNull(data, "查询专辑信息失败");
            BeanUtils.copyProperties(data,albumInfoIndex);

            //  将新增商品SKUID存入布隆过滤器
            //  获取布隆过滤器，将新增skuID存入布隆过滤器
//            RBloomFilter<Object> bloomFilter = redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER);
//            bloomFilter.add(data.getId());


            //获取属性与属性值信息
            albumInfoIndex.setAttributeValueIndexList(data.getAlbumAttributeValueVoList().stream().map(albumAttributeValue -> {
                AttributeValueIndex albumAttributeValue1 = new AttributeValueIndex();
                albumAttributeValue1.setValueId(albumAttributeValue.getValueId());
                albumAttributeValue1.setAttributeId(albumAttributeValue.getAttributeId());
                return albumAttributeValue1;
            }).collect(Collectors.toList()));

            return data;
        },threadPoolExecutorConfig.threadPoolExecutor()).exceptionally(throwable -> {
            log.error("查询专辑信息失败：{}",throwable.getMessage());
            return null;
        });

        //根据id获取属性信息


//        Result albumInfo = albumInfoFeignClient.getAlbumInfo(albumId);

        //根据三级分类id查询视图就可以了
        CompletableFuture<Integer> exceptionally1 = albumInfoCompletableFuture.thenApplyAsync((albumInfo) -> {
            //远程调用根据三级分类ID 获取分类数据；
            Result<BaseCategoryView> baseCategoryView = categoryFeignClient.getBaseCategoryView(albumInfoIndex.getCategory3Id());
            //判断 当前数据
            Assert.notNull(baseCategoryView, "查询数据失败");
            BaseCategoryView data = baseCategoryView.getData();
            Assert.notNull(data, "查询分类数据失败");
            albumInfoIndex.setCategory1Id(data.getCategory1Id());
            albumInfoIndex.setCategory2Id(data.getCategory2Id());

//            BeanUtils.copyProperties(data, albumInfoIndex);
            return 1;
        }, threadPoolExecutorConfig.threadPoolExecutor()).exceptionally(throwable -> {
            log.error("查询分类数据失败：{}", throwable.getMessage());
            return 0;
        });

        Long category3Id = albumInfoIndex.getCategory3Id();

        //获取用户id
        CompletableFuture<Integer> exceptionally = albumInfoCompletableFuture.thenApplyAsync((albumInfo) -> {
            Result<UserInfoVo> userInfo = userInfoFeignClient.getUserInfo(albumInfo.getUserId());
            Assert.notNull(userInfo, "查询作者信息失败");

            UserInfoVo data = userInfo.getData();
            Assert.notNull(data, "查询作者信息失败");

            String nickname = data.getNickname();
            albumInfoIndex.setAnnouncerName(nickname);
            return 1;
        }, threadPoolExecutorConfig.threadPoolExecutor()).exceptionally(throwable -> {
            log.error("查询分类数据失败：{}", throwable.getMessage());
            return 0;
        });

        //统计信息：根据专辑Id 查询专辑的统计数据；
        CompletableFuture<Integer> exceptionally2 = CompletableFuture.supplyAsync(() -> {
            Result<AlbumStatVo> albumStatVo = albumInfoFeignClient.getAlbumStatVo(albumId);
            Assert.notNull(albumStatVo, "查询统计信息失败");
            AlbumStatVo data = albumStatVo.getData();
            Assert.notNull(data, "查询统计信息失败");
            albumInfoIndex.setPlayStatNum(data.getPlayStatNum());
            albumInfoIndex.setSubscribeStatNum(data.getSubscribeStatNum());
            albumInfoIndex.setBuyStatNum(data.getBuyStatNum());
            albumInfoIndex.setCommentStatNum(data.getCommentStatNum());
//            BeanUtils.copyProperties(data, albumInfoIndex);
            //设置热度
            albumInfoIndex.setHotScore(new Random().nextDouble(100000));
            return 1;
        }, threadPoolExecutorConfig.threadPoolExecutor()).exceptionally(throwable -> {
            log.error("查询作者信息失败：{}", throwable.getMessage());
            return 0;
        });
//        CompletableFuture.allOf(albumInfoCompletableFuture,exceptionally1,exceptionally,exceptionally2);
        //利用es的api进行数据保存，：albumInfoIndex --->es;
        try {
            if (null==albumInfoCompletableFuture.get()||0 == exceptionally1.get()||0==exceptionally.get()||0==exceptionally2.get()){
                //获取专辑失败：

                throw new GuiguException(20001,"远程调用获取数据失败");
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
        albumIndexRepository.save(albumInfoIndex);

        //上架提出库：|keyword|
        SuggestIndex suggestIndex = new SuggestIndex();
        //赋值：本质赋值的是title;
        suggestIndex.setId(UUID.randomUUID().toString().replace("-",""));
        suggestIndex.setTitle(albumInfoIndex.getAlbumTitle());
        suggestIndex.setKeyword(new Completion(new String[]{albumInfoIndex.getAlbumTitle()}));
        suggestIndex.setKeywordPinyin(new Completion(new String[]{PinYinUtils.toHanyuPinyin(albumInfoIndex.getAlbumTitle())}));
        suggestIndex.setKeywordSequence(new Completion(new String[]{PinYinUtils.getFirstLetter(albumInfoIndex.getAlbumTitle())}));
        suggestIndexRepository.save(suggestIndex);
        // 介绍;
        SuggestIndex suggestIndexInfo = new SuggestIndex();
        //赋值：本质赋值的是title；
        suggestIndexInfo.setId(UUID.randomUUID().toString().replace("-",""));
        suggestIndex.setTitle(albumInfoIndex.getAlbumIntro());
        suggestIndex.setKeyword(new Completion(new String[]{albumInfoIndex.getAlbumIntro()}));
        suggestIndex.setKeywordPinyin(new Completion(new String[]{PinYinUtils.toHanyuPinyin(albumInfoIndex.getAlbumIntro())}));
        suggestIndex.setKeywordSequence(new Completion(new String[]{PinYinUtils.getFirstLetter(albumInfoIndex.getAlbumIntro())}));
        suggestIndexRepository.save(suggestIndexInfo);
        //作者
        SuggestIndex suggestIndexAuth = new SuggestIndex();
        suggestIndexAuth.setId(UUID.randomUUID().toString().replace("-",""));
        suggestIndex.setTitle(albumInfoIndex.getAnnouncerName());
        suggestIndex.setKeyword(new Completion(new String[]{albumInfoIndex.getAnnouncerName()}));
        suggestIndex.setKeywordPinyin(new Completion(new String[]{PinYinUtils.toHanyuPinyin(albumInfoIndex.getAnnouncerName())}));
        suggestIndex.setKeywordSequence(new Completion(new String[]{PinYinUtils.getFirstLetter(albumInfoIndex.getAnnouncerName())}));
        suggestIndexRepository.save(suggestIndexAuth);



    }

    @Override
    @Async//异步方法
    public void lowerAlbum(Long albumId) {
        // 利用es 的api进行删除数据：albumInfoIndex-->es;
        albumIndexRepository.deleteById(albumId);
    }

    @Override
    public AlbumSearchResponseVo search(AlbumIndexQuery albumIndexQuery) {
        //构建dsl语句
        SearchRequest request = buildQueryDsl(albumIndexQuery);
        //调用查询方法
        SearchResponse<AlbumInfoIndex> response = null;
        try {
            response=elasticsearchClient.search(request, AlbumInfoIndex.class);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        //得到返回的结果集
        AlbumSearchResponseVo responseVo = parseSearchRequest(response);
        responseVo.setPageSize(albumIndexQuery.getPageSize());
        responseVo.setPageNo(albumIndexQuery.getPageNo());
        //获取总页数
        long totalPages = (responseVo.getTotal()+albumIndexQuery.getPageSize()-1)/albumIndexQuery.getPageSize();
        responseVo.setTotalPages(totalPages);

        return responseVo;
    }

    @Override
    public List<String> completeSuggest(String keyword) {
        //Java动态生成dsl语句
        SearchRequest.Builder searchRequest = new SearchRequest.Builder();
        searchRequest.index("suggestinfo").suggest(
                s->s
                        .suggesters("suggestionKeyword",f->f.prefix(keyword).completion(
                        c->c.field("keyword").skipDuplicates(true).size(10)
                                .fuzzy(
                                z->z.fuzziness("auto"))
                ))
                        .suggesters("suggestionkeywordPinyin",f->f.prefix(keyword).completion(
                        c->c.field("keywordPinyin").skipDuplicates(true).size(10)
                                .fuzzy(
                                z->z.fuzziness("auto"))
                ))
                        .suggesters("suggestionkeywordSequence",f->f.prefix(keyword).completion(
                        c->c.field("keywordSequence").skipDuplicates(true).size(10).fuzzy(
                                z->z.fuzziness("auto")
                        )
                ))
        );

        //获取查询结果
        SearchResponse<SuggestIndex> searchResponse = null;
        try {
            searchResponse =elasticsearchClient.search(searchRequest.build(),
                    SuggestIndex.class);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        //获取到结果，数据转换。set集合无序不重复，1.hashCode();2.equals();
        //为什么底层hashMap！map.key = value map.value = new Object();
        ArrayList<String> titleList = new ArrayList<>();
        titleList.addAll(this.parseRequestData(searchResponse,"suggestionKeyword"));
        titleList.addAll(this.parseRequestData(searchResponse,"suggestionkeywordPinyin"));
        titleList.addAll(this.parseRequestData(searchResponse,"suggestionkeywordSequence"));



        return titleList;
    }
    @Override
    public List<Map<String, Object>> channel(Long category1Id) {
        //  map.put("baseCategory3",三级分类对象);   map.put("list",专辑集合列表);
        //  从mapkey 对应的value 入手分析实现过程!
        //  1.  通过一级分类Id获取到三级分类列表;
        Result<List<BaseCategory3>> baseCategory3ListResult = categoryFeignClient.findTopBaseCategory3(category1Id);

        //  判断：
        Assert.notNull(baseCategory3ListResult, "查询三级分类集合失败");
        //  findTopBaseCategory3 limit 7 --> 有七条数据; 1001 ... 1007
        List<BaseCategory3> baseCategory3List = baseCategory3ListResult.getData();
        Assert.notNull(baseCategory3List, "查询三级分类集合失败");
        //  通过这个集合获取到三级分类Id集合：
        List<Long> category3IdList = baseCategory3List.stream().map(BaseCategory3::getId).collect(Collectors.toList());
        //  通过三级分类Id查找三级分类对象; category3Id -> BaseCategory3;
        //  baseCategory3List-->Map(key=category3Id,BaseCategory3); Function.identity()：t -> t
        Map<Long, BaseCategory3> category3Map = baseCategory3List.stream().collect(Collectors.toMap(BaseCategory3::getId, Function.identity()));

        //  List<Long>-->List<FieldValue> FieldValue.of(BaseCategory3::getId)
        List<FieldValue> fieldValueList = baseCategory3List.stream().map(baseCategory3 -> FieldValue.of(baseCategory3.getId())).collect(Collectors.toList());
        //  专辑集合列表
        SearchResponse<AlbumInfoIndex> searchResponse = null;
        try {
            searchResponse = elasticsearchClient.search(s -> s.index("albuminfo")
                            .query(q -> q.terms(t -> t.field("category3Id")
                                    .terms(t1 -> t1.value(fieldValueList))))
                            .aggregations("agg_category3Id", a -> a.terms(t -> t.field("category3Id"))
                                    .aggregations("topSixHotScoreAgg", a1 -> a1.topHits(t1 -> t1.size(6)
                                            .sort(s1 -> s1.field(f -> f.field("hotScore").order(SortOrder.Desc)))))
                            )
                    ,
                    AlbumInfoIndex.class);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        //  获取结果组装数据;
        Aggregate aggregate = searchResponse.aggregations().get("agg_category3Id");
        List<Map<String, Object>> list = aggregate.lterms().buckets().array().stream().map(bucket -> {
            //  存储数据；需要创建一个map集合：
            HashMap<String, Object> map = new HashMap<>();
            //  先获取key;
            long category3Id = bucket.key();
            //  存储第一个数据三级分类对象： baseCategory3.name
            map.put("baseCategory3", category3Map.get(category3Id));
            //  获取专辑集合列表;
            Aggregate topSixHotScoreAgg = bucket.aggregations().get("topSixHotScoreAgg");
            List<AlbumInfoIndex> albumInfoIndexList = topSixHotScoreAgg.topHits().hits().hits().stream().map(hit -> JSON.parseObject(hit.source().toString(), AlbumInfoIndex.class)).collect(Collectors.toList());
            map.put("list", albumInfoIndexList);
            //  返回map;
            return map;
        }).collect(Collectors.toList());
        //  返回数据
        return list;
    }

    @Override
    public List<AlbumInfoIndex> findRankingList(Long category1Id, String rangking) {
        //hget key field
        return (List<AlbumInfoIndex>) redisTemplate.opsForHash().get(RedisConstant.RANKING_KEY_PREFIX+category1Id,rangking);
    }

    @Override
    public void updateLatelyAlbumRanking() {
        //  1.获取所有一级分类数据：select * from base_category1;
       Result<List<BaseCategory1>> listResult= categoryFeignClient.findAllCategory1();
       Assert.notNull(listResult,"查询一级分类数据失败");
        List<BaseCategory1> baseCategory1List = listResult.getData();
        Assert.notNull(baseCategory1List,"查询一级分类数据失败");
        //获取排序的维度：
        String[] split = rankingDimensionArray.split(",");
        //循环变量集合 调用es客户端生成dsl语句并执行获取结果集并放入缓存；
        for (BaseCategory1 baseCategory1 : baseCategory1List) {
            //获取一级分类Id
            Long category1Id = baseCategory1.getId();
            for (String rangking : split) {
                //调用es api
                SearchResponse<AlbumInfoIndex> searchResponse = null;
                try {
                    searchResponse = elasticsearchClient.search(
                            s->s.index("albuminfo")
                                    .query(q->q.term(t->t.field("category1Id").value(category1Id)))
                                    .sort(s1->s1.field(f->f.field(rangking).order(SortOrder.Desc)))
                            ,
                            AlbumInfoIndex.class);
                }catch (IOException e){
                    throw new RuntimeException();
                }
                //获取集合列表
                List<AlbumInfoIndex> albumInfoIndexList = searchResponse.hits().hits().stream().map(Hit::source).collect(Collectors.toList());
                //将每次获取到的数据添加到缓存中
                redisTemplate.opsForHash().put(RedisConstant.RANKING_KEY_PREFIX+category1Id,rangking,albumInfoIndexList);
            }
        }
    }

//    @Override
//    public List<Map<String, Object>> channel(Long category1Id) {
//        //思路：
//        //1. 先根据一级分类Id获取到三级分类集合数据
//        Result<List<BaseCategory3>> baseCategory3ListResult=albumInfoFeignClient.findTopBaseCategory3(category1Id);
//        //7条数据，
//        List<BaseCategory3> baseCategory3List = baseCategory3ListResult.getData();
//        //建立对应关系key = 三级分类Id value = 三级分类对象
//        Map<Long,BaseCategory3> category3IdToMap= baseCategory3List.stream().collect(Collectors.toMap(BaseCategory3::getId,baseCategory3 -> baseCategory3));
//        //获取到三级分类Id集合
//        List<Long> idList = baseCategory3List.stream().map(BaseCategory3::getId).collect(Collectors.toList());
//        //将这个idList进行转换
//        List<FieldValue> valueList = idList.stream().map(id -> FieldValue.of(id)).collect(Collectors.toList());
//        //调查查询方法
//        SearchRequest.Builder request = new SearchRequest.Builder();
//        request.index("albuminfo").query(q->q.terms(f->f.field("category3Id").terms(new TermsQueryField.Builder().value(valueList).build())));
//        request.aggregations("agg_category3Id",a->a.terms(t->t.field("category3Id"))
//                .aggregations("topSixHotScoreAgg",a1->a1.topHits(s->s.size(6)
//                        .sort(sort->sort.field(f->f.field("hotScore").order(SortOrder.Desc)))))
//        );
//        //获取到查询结果集
//        SearchResponse<AlbumInfoIndex> searchResponse = null;
//        try {
//            searchResponse=elasticsearchClient.search(request.build(),AlbumInfoIndex.class);
//        } catch (IOException e) {
//            throw new RuntimeException(e);
//        }
//        //声明集合
//        List<Map<String,Object>> result = new ArrayList<>();
//        //从集合中获取数据
//        Aggregate groupByCategory3IdApp = searchResponse.aggregations().get("agg_category3Id");
//        groupByCategory3IdApp.lterms().buckets().array().forEach(item->{
//            //创建集合数据
//            List<AlbumInfoIndex> albumInfoIndexList=new ArrayList<>();
//            //获取三级分类Id对象
//            long category3Id = item.key();
//            //获取要置顶的集合数据
//            Aggregate topSixHotScoreAgg = item.aggregations().get("topSixHotScoreAgg");
//            //循环遍历获取集合中的数据
//            topSixHotScoreAgg.topHits().hits().hits().forEach(hit->{
//                //获取到source的json字符串数据
//                String json = hit.source().toString();
//                //将json字符串转换为AlbumInfoIndex对象
//                AlbumInfoIndex albumInfoIndex = JSON.parseObject(json, AlbumInfoIndex.class);
//                //将对象添加到集合中
//                albumInfoIndexList.add(albumInfoIndex);
//            });
//            //声明一个map集合数据
//            HashMap<String, Object> map = new HashMap<>();
//            //存储根据三级分类Id要找到的三级分类
//            map.put("baseCategory3",category3IdToMap.get(category3Id));
//            //存储所有的专辑集合数据
//            map.put("list",albumInfoIndexList);
//            //将map添加到集合中
//            result.add(map);
//        });
//        return result;
//    }

    private List<String> parseRequestData(SearchResponse<SuggestIndex> response, String suggestName) {
        //创建集合
        ArrayList<String> suggestList = new ArrayList<>();
        Map<String, List<Suggestion<SuggestIndex>>> groupBySuggestionListAggMap = response.suggest();
        groupBySuggestionListAggMap.get(suggestName).forEach(item->{
            CompletionSuggest<SuggestIndex> completionSuggest = item.completion();
            completionSuggest.options().forEach(it->{
                SuggestIndex suggestIndex = it.source();
                suggestList.add(suggestIndex.getTitle());
            });
        });
        //返回结合列表
        return suggestList;
    }


    private AlbumSearchResponseVo parseSearchRequest(SearchResponse<AlbumInfoIndex> searchResponse) {
        //创建对象
        AlbumSearchResponseVo searchResponseVo = new AlbumSearchResponseVo();
        //private List<AlbumInfoIndexVo> list = new ArrayList<>();
        //private Long total;//总记录数
        //获取数据
        HitsMetadata<AlbumInfoIndex> hits = searchResponse.hits();
        //总记录数
        searchResponseVo.setTotal(hits.total().value());
        //获取数据
        List<Hit<AlbumInfoIndex>> subHits = hits.hits();
        //判断
        if (!CollectionUtils.isEmpty(subHits)){
            //
            List<AlbumInfoIndexVo> list = subHits.stream().map(albumInfoIndexHit -> {
                //创建对象
                AlbumInfoIndexVo albumInfoIndexVo = new AlbumInfoIndexVo();
                AlbumInfoIndex albumInfoIndex = albumInfoIndexHit.source();
                //进行复制
                BeanUtils.copyProperties(albumInfoIndex, albumInfoIndexVo);
                //判断用户是否根据关键词进行检索
                if (null != albumInfoIndexHit.highlight().get("albumTitle")) {
                    //获取高亮数据
                    String albumTitle = albumInfoIndexHit.highlight().get("albumTitle").get(0);
                    //赋值高亮数据
                    albumInfoIndexVo.setAlbumTitle(albumTitle);
                }
                //返回数据
                return albumInfoIndexVo;
            }).collect(Collectors.toList());
            //赋值
            searchResponseVo.setList(list);

        }
        return searchResponseVo;
    }

    /**
     * 获取查询请求 - 生成dsl语句
     * @param albumIndexQuery
     * @return
     */
    private SearchRequest buildQueryDsl(AlbumIndexQuery albumIndexQuery){
        //检索入口：关键词
        String keyword = albumIndexQuery.getKeyword();
        SearchRequest.Builder requestBuilder = new SearchRequest.Builder();
        // {query - bool}
        BoolQuery.Builder boolQuery = new BoolQuery.Builder();
        if (!StringUtils.isEmpty(keyword)){
            boolQuery.should(s->{return s.match(f-> f.field("albumTitle").query(keyword));});
            boolQuery.should(s->{return s.match(f-> f.field("albumIntro").query(keyword));});
            requestBuilder.highlight(h->h.fields("albumTitle", f->f.preTags("<span style=color:red>").postTags("</span>")));
        }

        //入口：分类Id 复制小括号，写死右箭头，落地大括号
        //一级分类
        Long category1Id = albumIndexQuery.getCategory1Id();
        if (!StringUtils.isEmpty(category1Id)){
            boolQuery.filter(f->f.term(t->t.field("category1Id").value(category1Id)));
        }
        //二级分类
        Long category2Id = albumIndexQuery.getCategory2Id();
        if (!StringUtils.isEmpty(category2Id)){
            boolQuery.filter(f->f.term(t->t.field("category2Id").value(category2Id)));
        }
        //三级分类
        Long category3Id = albumIndexQuery.getCategory3Id();
        if (!StringUtils.isEmpty(category3Id)){
            boolQuery.filter(f->f.term(t->t.field("category3Id").value(category3Id)));
        }
        //根据属性Id检索，前端传递数据的时候 属性Id：属性值Id 属性Id：属性值Id
        List<String> attributeList = albumIndexQuery.getAttributeList();
        if (!CollectionUtils.isEmpty(attributeList)){
            attributeList.stream()
                    .map(f->{
                        String[] split = f.split(":");
                        if (null !=split &&split.length==2){
                            NestedQuery nestedQuery = NestedQuery.of(fa -> fa.path("attributeValueIndexList")
                                    .query(f1 -> f1.bool(
                                            f2 -> f2.must(f3 -> f3.match(f4 -> f4.field("attributeValueIndexList.attributeId").query(split[0])))
                                                    .must(f4 -> f4.match(f5 -> f5.field("attributeValueIndexList.valueId").query(split[1])))
                                    ))
                            );
                            boolQuery.filter(fb->fb.nested(nestedQuery));

                        }
                        return null;
                    });
        }
        //排序 分页 高亮 排序（综合排序[1:desc] 播放量[2:desc] 发布时间[3:desc]；asc升序 desc降序）
        String order = albumIndexQuery.getOrder();
        //定义一个排序字段
        String orderField = "";
        //定义一个排序规则
        String sort = "";
        //判断
        if (!StringUtils.isEmpty(order)){
            //分割数据
            String [] split = order.split(":");
            if (null !=split &&split.length==2){
                switch (split[0]){
                    case "1"-> orderField = "hotScore";
                    case "2"-> orderField = "playStatNum";
                    case "3"-> orderField = "createTime";
                }
                sort = split[1];
            }
            //  判断 desc SortOrder.Desc asc SortOrder.Asc
            String finalSort = sort;
            String finalOrderField = orderField;
            requestBuilder.sort(f->f.field(o->o.field(finalOrderField).order("asc".equals(finalSort)? SortOrder.Asc:SortOrder.Desc)));
        }else {
            //默认排序规则 _score
            requestBuilder.sort(f->f.field(o->o.field("_score").order(SortOrder.Desc)));
        }
        //字段选择
        requestBuilder.source(s->s.filter(f->f.excludes("attributeValueIndexList")));
        //分页: (pageNo-1)*pageSize()
        int from = (albumIndexQuery.getPageNo() - 1) * albumIndexQuery.getPageSize();
        requestBuilder.from(from);
        requestBuilder.size(albumIndexQuery.getPageSize());
        //  {query  }
        //GET /albumInfo/_search
        requestBuilder.index("albuminfo").query(f->f.bool(boolQuery.build()));
        //创建对象
        SearchRequest searchRequest = requestBuilder.build();
        System.out.println("dsL:\t"+searchRequest.toString());
        //返回
        return searchRequest;

    }



//    public static void main(String[] args) {
////        ArrayList<AlbumAttributeValue> objects = new ArrayList<>();
////        AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
////        AlbumAttributeValueVo albumAttributeValueVo = new AlbumAttributeValueVo();
////        albumAttributeValue.setAttributeId(1L);
////        objects.add(albumAttributeValue);
////        ArrayList<AlbumAttributeValueVo> albumAttributeValueVos = new ArrayList<>();
////        BeanUtil.copyProperties(objects,albumAttributeValueVos);
////        System.out.println(objects);
////        System.out.println(albumAttributeValueVos);
//
//
//
////        AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
////        AlbumAttributeValueVo albumAttributeValueVo = new AlbumAttributeValueVo();
////        albumAttributeValue.setAttributeId(1L);
////        BeanUtil.copyProperties(albumAttributeValue,albumAttributeValueVo);
////        System.out.println(albumAttributeValue.getAttributeId());
////        System.out.println(albumAttributeValueVo.getAttributeId());
////        AlbumInfoIndex albumInfoIndex = new AlbumInfoIndex();
////        AlbumInfo albumInfo = new AlbumInfo();
////        ArrayList<AttributeValueIndex> objects = new ArrayList<>();
////        AttributeValueIndex albumAttributeValue = new AttributeValueIndex();
////        albumAttributeValue.setAttributeId(1L);
////        albumAttributeValue.setValueId(2L);
////        objects.add(albumAttributeValue);
////        albumInfoIndex.setAttributeValueIndexList(objects);
////        ArrayList<AlbumAttributeValue> objects1 = new ArrayList<>();
////        albumInfo.setAlbumAttributeValueVoList(objects1);
//
//        AlbumInfoIndex albumInfoIndex = new AlbumInfoIndex();
//        AlbumInfoIndex albumInfoIndex1 = new AlbumInfoIndex();
//        albumInfoIndex1.setCategory1Id(1L);
//        AlbumInfoIndex albumInfoIndex2 = new AlbumInfoIndex();
//        albumInfoIndex2.setCategory2Id(2L);
//
//        BeanUtil.copyProperties(albumInfoIndex1,albumInfoIndex);
//        System.out.println("==="+albumInfoIndex);
//        BeanUtil.copyProperties(albumInfoIndex2,albumInfoIndex);
//        System.out.println("==="+albumInfoIndex);
//
//    }
}
